home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1988 / 08 / ddj0888.src
C/C++ Source or Header  |  1988-08-03  |  73KB  |  2,679 lines

  1. /*
  2. [76703,4265]
  3. CCOL.LST                  01-Aug-88 1608
  4.  
  5.     Keywords: AUG88 C COLUMN STEVENS
  6.  
  7.     Source for Al Stevens C column in the August 1988 DDJ
  8.  
  9. EXAMPLE 1
  10. */
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <string.h>
  14.  
  15. char crypto [80];         /* encrypted message */
  16. char decoded [80];        /* decrypted message */
  17. char alphabet [] = "\nabcdefghijklmnopqrstuvwxyz";
  18. char subs []       = "                          ";
  19.  
  20. /* ------ ANSI.SYS screen driver ---------- */
  21. #define cursor(x,y) printf("\033[%02d;%02dH",y,x)
  22. #define clear_screen() puts("\033[2J")
  23.  
  24. main()
  25. {
  26.     int i, cp, a, b;
  27.     char sb [3];
  28.  
  29.     clear_screen();
  30.     cursor(1, 6);
  31.     puts("Enter the encrypted quote:\n");
  32.     fgets(crypto, 80, stdin);
  33.     for (i = 0; i < strlen(crypto); i++)
  34.         decoded[i] = ' ';                  /* clear the decrypted msg */
  35.     decoded[i] = '\0';
  36.     while (1)    {
  37.         cursor(1, 9);
  38.         puts(decoded);
  39.         puts(alphabet);                    /* display the alphabet */
  40.         puts(subs);                        /* display the substitutions */
  41.         puts("\nEnter 2 letter substitution: (xy):");
  42.         fgets(sb, 3, stdin);
  43.         if (strncmp(sb, "99", 2) == 0)
  44.             break;
  45.         a = *sb, b = *(sb+1);
  46.         if (isalpha(a) && isalpha(b))    {
  47.             for (cp = 0; cp < 26; cp++)
  48.                 if (subs[cp] == a)
  49.                     subs[cp] = ' ';
  50.             subs[b - 'a'] = a;
  51.             for (cp = 0; cp < strlen(crypto); cp++) {
  52.                 if (decoded[cp] == b)
  53.                     decoded[cp] = ' ';
  54.                 if (tolower(crypto[cp]) == a)
  55.                     decoded[cp] = b;
  56.             }
  57.         }
  58.     }
  59. }
  60.  
  61. /*
  62. [76703,4265]
  63. CRYPTO.LST                01-Aug-88 3552
  64.  
  65.     Keywords: AUG88 CRYPTOGRAPHY
  66.  
  67.     Source from Micheners article on Enigma style encryption.
  68.  
  69. _A TOOL FOR SECRET KEY CRYPTOGRAPHY_
  70. by
  71. John R. Michener
  72.  
  73. LISTING 1
  74. */
  75.  
  76. /* -------------------- Listing 1 -----------------------------*/
  77. /* this routine uses a supplied file (n>64K) of random one byte
  78. numbers to generate a set of encryption and
  79. decryption rotors.  These rotors are supplied sequentially in a
  80. 128K file.  The first 64K of the file contains
  81. the encryption rotors in series, the second 64K contains the
  82. decryption rotors in series.  The order within the
  83. file is the 256 elements of the first rotor in sequence followed
  84. by the 256 elements of the second rotor, on
  85. through all the rotors in the set.
  86.  
  87. Since random files are not easily created by users it is
  88. necessary to create a close approximation to random
  89. files.  This can be done by taking a variety of text and program
  90. files, compressing them, encrypting them with
  91. random keys, and concatenating them to form a long binary file.
  92. If English text was the source material this
  93. compressed, binary file should be at least 256K bytes long
  94. (making allowances for the redundancy of English).
  95. The resulting 4:1 overlap of compressed English removes the
  96. redundancies and residual order present in the
  97. original language file.  The length of the binary file should be
  98. entered into the #define NN line since the
  99. binary nature of the file prevents EOF characters.  Use command
  100. line file direction to read the random file
  101. into the program and direct the output into the rotor file. */
  102.  
  103. #include <stdio.h>
  104. #define NN      /* length of random file in bytes */
  105.  
  106. main()
  107.     {
  108.     unsigned char rnd[65536];   /* random number array  */
  109.     unsigned char rotor[2*65536];
  110.     register int k, temp, c;
  111.     register long i, j;
  112.  
  113.     for(i=0, j=0; i<NN; i++)
  114.         {
  115.         rnd[j++] ^= ((unsigned char)(c=getchar()));
  116.         if (j==65536)
  117.             j = 0;
  118.         }
  119.  
  120.     for(i=0; i<65536; i+=256)
  121.         for(j=0; j<256; j++)
  122.             rotor[i+j] = j;
  123.  
  124.     for(i=0; i<65536; i+=256)
  125.         for(j=0; j<256; j++)
  126.             {
  127.             k=rnd[i+j];
  128.             temp = rotor[i+j];
  129.             rotor[i+j] = rotor[i+k];
  130.             rotor[i+k] = temp;
  131.             rotor[65536 + i + rotor[i+j]] = j;
  132.             rotor[65536 + i + rotor[i+k]] = k;
  133.             }
  134.  
  135.     for(i=0; i<2*65536; i++)
  136.         putchar(rotor[i]);
  137.     }
  138.  
  139. -------------------------------------------------------------------------
  140. /*
  141. LISTING 2
  142. */
  143. /* ----------------------------Listing 2 -------------------------------*/
  144. /* in the following subroutines the PR numbers used for GR
  145. operations are stored in rndout[] and are accessed
  146. by the offset values ro.  These values are incremented by 8 for
  147. each character processed to allow for the 8 PR
  148. numbers needed per GR operation. */
  149.  
  150. /*________ character substitution encryption _________________*/
  151. unsigned char sub(ch,ro)
  152. unsigned char ch;       /* character to be encrypted */
  153. int ro;                 /* offset in random number array */
  154.     {
  155.     int i;
  156.  
  157.     for(i=0;i<4;i++)
  158. ch=rotor[(int)((rndout[i+ro])<<8)+(int)((rndout[i+4+ro]+ch)&255)];
  159.     return(ch);
  160.     }
  161.  
  162. /*__________ character substitution decryption _____________*/
  163. unsigned char unsub(ch,ro)
  164. unsigned char ch;       /* character to be decrypted */
  165. int ro;                 /* offset in random number array */
  166.     {
  167.     int i;
  168.  
  169.     for(i=3;i>=0;i--)
  170. ch=(rotor[65536+(int)((rndout[i+ro])<<8)+(int)ch]-rndout[i+4+ro])&255;
  171.     return(ch);
  172.     }
  173.  
  174. /*
  175. [76703,4265]
  176. FINDFU.LST                01-Aug-88 26692              Accesses: 27
  177.  
  178.     Keywords: AUG88
  179.  
  180.     Source code for the article Find that Function in the August 1988 issue of
  181.     DDJ
  182.  
  183. _FIND THAT FUNCTION_
  184. by
  185. Marvin Hymowech
  186.  
  187. LISTING 1
  188. */
  189. /*
  190.  * bldfuncs.c: Construct a table of the functions defined in source files.
  191.  * Copyright (c) 1988 Marvin Hymowech
  192.  *
  193.  * Usage:   bldfuncs file1.c file2.c ...
  194.  *          (wildcards are allowed also, e.g. *.c )
  195.  *          The output table is named funcs.txt.
  196.  */
  197.  
  198. #include <stdio.h>
  199. #include <ctype.h>
  200. #include <string.h>
  201. #define LINT_ARGS
  202.  
  203. #define TRUE      1
  204. #define FALSE     0
  205. #define OK        0
  206. #define ERROR     1
  207.  
  208. /* return values for filter functions below.
  209.  * EOF or any character is also possible.
  210.  */
  211. #define BRACES    -2
  212. #define PARENS    -3
  213. #define QUOTES    -4
  214.  
  215. /* function declarations for type checking */
  216. char *get_fn_name(char *);
  217. int get_names_one_file(char *, FILE *);
  218.  
  219. main(argc, argv)
  220. int argc;
  221. char **argv;
  222. {
  223.    FILE *fp_out;
  224.    char *current_file;
  225.    int num_files, i;
  226.  
  227.    if( argc < 2 )
  228.    {
  229.       fprintf( stderr, "wrong number of parameters" );
  230.       exit(1);
  231.    }
  232.  
  233.    if( (fp_out = fopen("funcs.txt", "w")) == NULL )
  234.    {
  235.       fprintf( stderr, "can't open %s\n", "funcs.txt" );
  236.       exit(1);
  237.    }
  238.  
  239.    /* build a function list for each file on the command line,
  240.     * and write the list to the file funcs.txt.
  241.     */
  242.    printf( "Creating funcs.txt...\n" );
  243.    num_files = argc - 1;
  244.    for ( i = 1; i <= num_files; i++ )
  245.    {                                /* tell the user where we're at */
  246.       printf( "%30s: %3d of %3d files\n",
  247.                            current_file = strlwr(*++argv), i, num_files );
  248.       if( get_names_one_file( current_file, fp_out ) != OK )
  249.       {     /* use strlwr to lower-case the name - cosmetic only */
  250.          fprintf( stderr, "can't process %s", current_file );
  251.          exit(1);
  252.       }
  253.    }
  254.  
  255.    fclose(fp_out);
  256.    exit(0);
  257. }
  258.  
  259. /* open the .c file source_file_name, scan it for function definitions,
  260.  * and write a listing to fp_out in the form:
  261.  *          source_file_name:
  262.  *             function-1
  263.  *             function-2 ...
  264.  *             function-n;
  265.  * Return values: OK or ERROR
  266.  */
  267. int
  268. get_names_one_file(source_file_name, fp_out)
  269. char *source_file_name;
  270. FILE *fp_out;
  271. {
  272.    int line_len, c, got_fn_defn = FALSE;
  273.    #define LINE_LEN 8192
  274.    char line[LINE_LEN], *name_ptr, fn_name[64];
  275.    FILE *fp_source;
  276.                                           /* open the input source file */
  277.    if( (fp_source = fopen(source_file_name, "r")) == NULL )
  278.       return ERROR;
  279.                                           /* write "source file name:" */
  280.    sprintf( line, "\n%s:", source_file_name );
  281.    fprintf( fp_out, line );
  282.  
  283.    while( TRUE )
  284.    {
  285.       line_len = 0;           /* using the filter_data() char stream */
  286.                               /* collect chars until a semicolon or PARENS */
  287.       while( (c = filter_data(fp_source)) != EOF && c != ';' && c != PARENS )
  288.          line[line_len++] = c;
  289.       if( c == EOF )
  290.          break;
  291.       if( c == ';' )          /* Bypass externals representing data items. */
  292.          continue;            /* Now we know line ended with PARENS. */
  293.       line[ line_len ] = 0;   /* Terminate line. */
  294.  
  295.          /* At this point, line either contains a function definition
  296.           * or a function type declaration or something else, perhaps
  297.           * an occurrence of parenthese in a data item definition.
  298.           * We only want function definitions.
  299.           */
  300.                         /* Extract the function name from this possible */
  301.                         /* function definition, and save it in fn_name. */
  302.       strcpy( fn_name, get_fn_name(line) );
  303.                         /* Exclude the case of parenthetical expressions    */
  304.                         /* in a data defintion, e.g. within array brackets. */
  305.       if( !fn_name[0] )
  306.          continue;
  307.                                        /* skip white space */
  308.       while( (c = filter_data(fp_source)) != EOF && isspace(c) )
  309.          ;
  310.       if( c == ';' || c == ',' )       /* functions type check declaration */
  311.          continue;                     /* so bypass it */
  312.       if( c == EOF )
  313.          break;
  314.                                        /* skip any parameter declarations - */
  315.       while( c != BRACES && c != EOF )    /* eat until braces or EOF */
  316.          c = filter_data(fp_source);
  317.  
  318.                      /* append this function definition to the output table */
  319.       fprintf( fp_out, "\n\t%s", fn_name );
  320.       got_fn_defn = TRUE;
  321.    }
  322.    fclose(fp_source);
  323.                               /* got_fn_defn FALSE if no functions in file */
  324.                                /* write file terminator */
  325.    fputs( got_fn_defn ? ";\n" : "\n\t;\n", fp_out );
  326.    return OK;
  327. }
  328.  
  329. /* assuming that the input line ends with a function name,
  330.  * extract and return this name (as a pointer into the input line).
  331.  */
  332. char *
  333. get_fn_name(line)
  334. char *line;
  335. {
  336.    char *name_ptr;
  337.    int len;
  338.  
  339.    if( !(len = strlen(line)) )
  340.       return line;
  341.  
  342.    name_ptr = line + len - 1;
  343.  
  344.    while( isspace(*name_ptr) )      /* skip trailing white space */
  345.       name_ptr--;
  346.    *(name_ptr + 1) = 0;             /* terminate fn name */
  347.  
  348.                                  /* function names consist entirely of */
  349.                                  /* alphanumeric characters and underscores */
  350.    while( (isalnum(*name_ptr) || *name_ptr == '_') && name_ptr >= line )
  351.       name_ptr--;
  352.                                  /* if this alleged function name begins */
  353.    if( isdigit(*++name_ptr) )    /* with a digit, return an empty string */
  354.       return( name_ptr + strlen(name_ptr) );
  355.    return name_ptr;              /* else return the function name */
  356. }
  357.  
  358. /* using the stream returned by filter_parens() as input,
  359.  * return a character stream in which any data initialization
  360.  * expressions between an equals sign and a semicolon
  361.  * have been replaced by a single semicolon.
  362.  * This will filter out anything involving parentheses in a
  363.  * data initialization expression, which might otherwise be
  364.  * mistaken for a function defintion.
  365.  */
  366. int filter_data(fp_source)
  367. FILE *fp_source;
  368. {
  369.    int c;
  370.  
  371.    if( (c = filter_parens(fp_source)) != '=' )
  372.       return c;
  373.    while( (c = filter_parens(fp_source)) != ';' && c != EOF )
  374.       ;
  375.    return c;
  376. }
  377.  
  378. /* using the stream returned by filter_curly_braces() as input,
  379.  * return a character stream in which all characters
  380.  * between '(' and the matching ')' have been replaced
  381.  * by the single special value PARENS (any nested parentheses within
  382.  * this top level pair will also have been eaten).
  383.  * This will filter out anything within the parentheses delimiting
  384.  * the arguments in a function definition.
  385.  */
  386. int
  387. filter_parens(fp_source)
  388. FILE *fp_source;
  389. {
  390.    int paren_cnt, c;
  391.  
  392.    if( (c = filter_curly_braces(fp_source)) != '(' )
  393.       return c;
  394.    paren_cnt = 1;
  395.    while( paren_cnt )
  396.       switch( filter_curly_braces(fp_source) )
  397.       {
  398.          case ')':
  399.             paren_cnt--;
  400.             break;
  401.          case '(':
  402.             paren_cnt++;
  403.             break;
  404.          case EOF:
  405.             return EOF;
  406.       }
  407.    return PARENS;
  408. }
  409.  
  410. /* using the stream returned by filter_ppdir() as input,
  411.  * return a character stream in which all characters
  412.  * between '{' and the matching '}' have been replaced
  413.  * by the single special value BRACES (any nested braces within
  414.  * this top level pair will also have been eaten).
  415.  * This will filter out anything internal to a function.
  416.  */
  417. int
  418. filter_curly_braces(fp_source)
  419. FILE *fp_source;
  420. {
  421.    int brace_cnt, c;
  422.  
  423.    if( (c = filter_ppdir(fp_source)) != '{' )
  424.       return c;
  425.    brace_cnt = 1;
  426.    while( brace_cnt )      /* wait for brace count to return to zero */
  427.       switch( filter_ppdir(fp_source) )
  428.       {
  429.          case '}':
  430.             brace_cnt--;   /* subtract right braces */
  431.             break;
  432.          case '{':
  433.             brace_cnt++;   /* add left braces */
  434.             break;
  435.          case EOF:
  436.             return EOF;
  437.       }
  438.    return BRACES;          /* brace count is now zero */
  439. }
  440.  
  441. #define MAXLINE 1024
  442.  
  443. /* using the stream returned by filter_quotes() as input,
  444.  * return a character stream in which all preprocessor
  445.  * directives have been eaten.
  446.  */
  447. int
  448. filter_ppdir(fp_source)
  449. FILE *fp_source;
  450. {
  451.    int c, i;
  452.    char line[MAXLINE + 1];
  453.  
  454.    while(TRUE)
  455.    {                    /* does this line begin a preprocessor directive? */
  456.       if( (c = filter_quotes(fp_source)) != '#' )
  457.          return c;      /* no, return character */
  458.                         /* yes, store until newline or EOF */
  459.       if( (c = get_ppdir_line( fp_source, line )) == EOF )
  460.          return EOF;
  461.       if( strncmp( line, "define", 6 ) )        /* if not #define directive */
  462.          continue;                              /* eat this line */
  463.       if( line[ strlen(line) - 1 ] != '\\' )    /* if #define line ends */
  464.          continue;                              /* with "\" */
  465.       else
  466.          while(TRUE)                            /* keep eating lines */
  467.          {                                      /* which also end with "\" */
  468.                                           /* store until newline or EOF */
  469.             if( (c = get_ppdir_line( fp_source, line )) == EOF )
  470.                return EOF;
  471.                            /* done with this #define directive if this */
  472.                            /* line is not also a continuation line */
  473.             if( line[ strlen(line) - 1 ] != '\\' )
  474.                break;
  475.          }
  476.    }
  477. }
  478.  
  479. /* Utility routine used by filter_ppdir() -
  480. /* read the character stream using filter_quotes, storing characters
  481.  * in the parameter "line", until EOF or '\n' is encountered.
  482.  * Return EOF or '\n' accordingly.
  483.  */
  484. int
  485. get_ppdir_line(fp_source, line)
  486. FILE *fp_source;
  487. char *line;
  488. {
  489.    int i, c;
  490.                                           /* store until newline or EOF */
  491.    for( i = 0; i < MAXLINE && (c = filter_quotes(fp_source)) != '\n'
  492.                                                          && c != EOF; i++ )
  493.       line[i] = c;
  494.    line[i] = 0;                           /* terminate string */
  495.    if( c == EOF )
  496.       return EOF;
  497.    return '\n';
  498. }
  499.  
  500. /* using the stream returned by filter_cmt() as input,
  501.  * return a character stream in which any quoted character
  502.  * or quoted string has been collapsed to the single special value QUOTES
  503.  * to avoid considering special characters like '{', '}', '(', or ')'
  504.  * which may occur within quotes.
  505.  */
  506. int
  507. filter_quotes(fp_source)
  508. FILE *fp_source;
  509. {
  510.    int c1, c2;
  511.  
  512.    if( (c1 = filter_cmt(fp_source)) != '\'' && c1 != '"' )
  513.       return c1;     /* pass char through if not single or double quote */
  514.    while( TRUE )
  515.       switch( c2 = filter_cmt(fp_source) )
  516.       {
  517.          case '\\':                 /* beginning of an escape sequence */
  518.             filter_cmt(fp_source);  /* so eat next char */
  519.             break;
  520.          case EOF:
  521.             return EOF;
  522.          default:
  523.             if( c2 == c1 )          /* found end of quoted char or string */
  524.                return QUOTES;
  525.       }
  526. }
  527.  
  528. /* Returns character stream, eating comments. */
  529. /* Returns EOF if end of file. */
  530. /* Nested comments are allowed. */
  531. int
  532. filter_cmt(fp_source)
  533. FILE *fp_source;
  534. {
  535.    /* values for state */
  536.    #define STABLE       0        /* not in process of changing the comment */
  537.                                  /* level: i.e., not in the middle of a    */
  538.                                  /* slash-star or star-slash combination.  */
  539.    #define IN_CMT_FS    1        /* got '/', looking for '*' */
  540.    #define OUT_CMT_STAR 2        /* got '*', looking for '/' */
  541.  
  542.    int c, state = STABLE, cmt_level = 0;
  543.  
  544.    while( TRUE )
  545.    {
  546.       c = fgetc(fp_source);
  547.       if( c == EOF )
  548.          return EOF;
  549.  
  550.       switch(state)
  551.       {
  552.          case STABLE:
  553.             if( c == '*' )
  554.                state = OUT_CMT_STAR;
  555.             else if( c == '/' )
  556.                state = IN_CMT_FS;
  557.             break;
  558.  
  559.          case IN_CMT_FS:
  560.             if( c == '*' )
  561.             {
  562.                state = STABLE;
  563.                cmt_level++;            /* descend one comment level  */
  564.                continue;
  565.             }
  566.             else if( !cmt_level )      /* if '/' not followed by '*' */
  567.             {                          /* and outside any comment    */
  568.                ungetc( c, fp_source ); /* push back this char        */
  569.                return '/';             /* and return the '/'         */
  570.             }
  571.             else if( c != '/' )        /* stay in state IN_CMT_FS     */
  572.                state = STABLE;         /* if next char is '/' as well */
  573.             break;
  574.  
  575.          case OUT_CMT_STAR:
  576.             if( c == '/' )
  577.             {
  578.                cmt_level--;         /* ascend one comment level */
  579.                state = STABLE;
  580.                continue;
  581.             }
  582.             else if( !cmt_level )      /* if '*' not followed by '/' */
  583.             {                          /* and outside any comment    */
  584.                ungetc( c, fp_source ); /* push back this char        */
  585.                return '*';             /* and return the '*'         */
  586.             }
  587.             else if( c != '*' )        /* stay in state IN_CMT_FS     */
  588.                state = STABLE;         /* if next char is '*' as well */
  589.             break;
  590.       }
  591.       if( state == STABLE && !cmt_level )    /* if outside any comment */
  592.          return c;                           /* return character */
  593.    }
  594. }
  595.  
  596. /*
  597. LISTING 2
  598.  
  599. NAME:   bldfuncs - construct a table of C source file names together with
  600.         a list of the names of all functions defined in these source files.
  601.  
  602. USAGE:  bldfuncs source_file_1 source_file_2 ...
  603.         (wildcard characters are allowed)
  604.  
  605. DESCRIPTION:    bldfuncs is used to construct the list file needed by getf.
  606.         The output file is named "funcs.txt", and has the format:
  607.  
  608.                 source_file_1.c:
  609.                         function_1
  610.                         function_2
  611.                         ...
  612.                         function_n;
  613.  
  614.                 source_file_2.c:
  615.                         ...
  616.  
  617.         Of course this file could be constructed or modified using a
  618.         text editor, but bldfuncs is designed to automate this process.
  619.         bldfuncs is run at relatively infrequent intervals to update
  620.         the list file, whereas getf is run frequently to locate functions.
  621.  
  622. EXAMPLES:       bldfuncs *.c            This will construct a funcs.txt file
  623.                                         in the current directory which will
  624.                                         contain a list of all .c files in
  625.                                         that directory, together with a list
  626.                                         of the functions defined in these
  627.                                         files.
  628.  
  629.                 bldfuncs *.c \source1\*.c \source2\*.c
  630.                                         This will construct a funcs.txt file
  631.                                         in the current directory which will
  632.                                         contain the above information for
  633.                                         the current directory, \source1,
  634.                                         and \source2 combined.
  635.  
  636.                 bldfuncs prog1.c prog2.c prog3.c
  637.                                         This will construct a funcs.txt file
  638.                                         in the current directory which will
  639.                                         contain the above information for
  640.                                         the selected files prog1.c, prog2.c
  641.                                         and prog3.c combined.
  642.  
  643. LISTING 3
  644. */
  645. /*
  646.  * getf.c - locate the source file containing a specified function and
  647.  *          present it in your favorite editor.
  648.  * Copyright (c) 1988 Marvin Hymowech
  649.  */
  650.  
  651. #include <stdio.h>
  652. #include <stdlib.h>
  653. #include <string.h>
  654. #define LINT_ARGS
  655.  
  656. #define TRUE      1
  657. #define FALSE     0
  658. #define LINE_LEN 256
  659.  
  660.    /* function declarations */
  661. int patn_match(char *, char *);
  662. void edit( char *, char * );
  663. void ask_for_file(char **, char **, unsigned int);
  664.  
  665. unsigned int num_ctl_patns;      /* number of %s symbols in GETFEDIT var */
  666. char *file_token, *func_token;
  667. char arg1[64];                   /* argument for editor command line */
  668. char *arg1_ctl;                  /* ctl string for building arg1 */
  669. char *pgm_name;                  /* name of editor to invoke */
  670.  
  671. main(argc, argv)
  672. int argc;
  673. char **argv;
  674. {
  675.    char file_line[LINE_LEN], func_line[LINE_LEN];
  676.    char func_name[64], edit_cmd[128];
  677.    char *env_edit_cmd, *ctl_patn;
  678.    unsigned int last_func, len, eof = FALSE;
  679.    static char file_name[] = "funcs.txt"; /* input file name */
  680.    FILE *funcs_file;
  681.    static char delim[] = "\n\t ";   /* white space delimiters */
  682.    #define MAX_CHOICES 256
  683.    unsigned int num_choices = 0;
  684.    char *func_choices[ MAX_CHOICES ], *file_choices[ MAX_CHOICES ];
  685.  
  686.  
  687.    if( argc != 2 )
  688.    {
  689.       fprintf( stderr, "getf: wrong number of arguments" );
  690.       exit(1);
  691.    }
  692.  
  693.       /* the argument is the function name to find */
  694.    strcpy( func_name, *++argv );
  695.  
  696.    if( (env_edit_cmd = getenv( "GETFEDIT" )) == NULL )
  697.    {
  698.       fprintf( stderr, "getf: missing environment variable GETFEDIT" );
  699.       exit(1);
  700.    }
  701.  
  702.       /* check if GETFEDIT environment variable has a place for
  703.        * function name as well as file name - note function name
  704.        * is assumed to go in the first %s pattern if there are
  705.        * two %s patterns.
  706.        */
  707.    if( (ctl_patn = strstr( env_edit_cmd, "%s" )) == NULL )
  708.    {
  709.       fprintf( stderr,
  710.                "getf: environment variable GETFEDIT has no %%s pattern" );
  711.       exit(1);
  712.    }
  713.  
  714.    num_ctl_patns = strstr( ++ctl_patn, "%s" ) == NULL ? 1 : 2;
  715.    strcpy( edit_cmd, env_edit_cmd );
  716.    if( (pgm_name = strtok( edit_cmd, " " )) == NULL )
  717.    {
  718.       fprintf( stderr,
  719.                "getf: environment variable GETFEDIT has incorrect format" );
  720.       exit(1);
  721.    }
  722.             /* point to argument following program name */
  723.    arg1_ctl = edit_cmd + strlen(pgm_name) + 1;
  724.  
  725.    if( (funcs_file = fopen( file_name, "r" )) == NULL )
  726.    {
  727.       fprintf( stderr, "getf: can't open %s\n", *argv );
  728.       exit(1);
  729.    }
  730.  
  731.    while( !eof )     /* loop thru file names, which end with colon */
  732.    {
  733.       if( fgets( file_line, LINE_LEN, funcs_file ) == NULL )
  734.          break;
  735.                      /* bypass any line consisting of white space */
  736.       if( (file_token = strtok( file_line, delim )) == NULL )
  737.          continue;
  738.  
  739.       if( file_token[ len = strlen(file_token) - 1 ] != ':' )
  740.       {
  741.          fprintf(stderr, "getf: incorrect file format on %s", file_name);
  742.          exit(1);
  743.       }
  744.       file_token[ len ] = 0;  /* kill trailing colon */
  745.       last_func = FALSE;   /* set up to detect last func this file */
  746.  
  747.       while( !eof && !last_func )   /* loop thru func names this file */
  748.       {                             /* last such ends with semicolon */
  749.          if( fgets( func_line, LINE_LEN, funcs_file ) == NULL )
  750.          {
  751.             eof = TRUE;
  752.             break;
  753.          }
  754.                      /* bypass any line consisting of white space */
  755.          if( (func_token = strtok( func_line, delim )) == NULL )
  756.             continue;
  757.  
  758.          if( func_token[ len = strlen(func_token) - 1 ] == ';' )
  759.          {
  760.             last_func = TRUE;          /* break loop after this one */
  761.             func_token[ len ] = 0;     /* kill trailing semi-colon */
  762.          }
  763.  
  764.          if( patn_match( func_name, func_token ) )
  765.          {
  766.             func_choices[num_choices] = strdup( func_token );
  767.             file_choices[num_choices++] = strdup( file_token );
  768.          }
  769.       }
  770.    }
  771.  
  772.    switch( num_choices )
  773.    {
  774.       case 0:
  775.          fprintf( stderr, "getf: no match for %s in %s",
  776.                                                       func_name, file_name );
  777.          exit(1);
  778.       case 1:
  779.          edit( func_choices[0], file_choices[0] );
  780.       default:
  781.          ask_for_file(func_choices, file_choices, num_choices);
  782.    }
  783. }
  784.  
  785. /* return TRUE if string s matches pattern patn,
  786.  * or FALSE if it does not.  Allowable wildcards
  787.  * in patn are: ? for any one character, % for
  788.  * any string of characters up to the next underscore
  789.  * or end of string, and * for any string of characters
  790.  * up to end of string.
  791.  */
  792. int
  793. patn_match(patn, s)
  794. char *patn;    /* pattern */
  795. char *s;       /* string */
  796. {
  797.    for( ; *patn; patn++ )
  798.    {
  799.       if( !*s )               /* if out of s chars, no match */
  800.          return                /* unless patn ends with * or % */
  801.             ((*patn == '*' || *patn == '%') && !*(patn + 1) );
  802.  
  803.       switch( *patn )
  804.       {
  805.          case '%':
  806.             while( *s != '_' && *s )
  807.                s++;
  808.             break;
  809.          case '*':
  810.             while( *s++ )
  811.                ;
  812.             break;
  813.          case '?':
  814.             s++;
  815.             break;
  816.          default:
  817.             if( *s != *patn )
  818.                return FALSE;
  819.             s++;
  820.       }
  821.    }
  822.    return *s == 0;
  823. }
  824.  
  825. void
  826. ask_for_file(func_choices, file_choices, num_choices)
  827. char *func_choices[], *file_choices[];
  828. unsigned int num_choices;
  829. {
  830.    int i;
  831.    char line[LINE_LEN];
  832.  
  833.    while( TRUE )
  834.    {
  835.       printf( "Which one? (CR to exit)\n" );
  836.       for( i = 1; i <= num_choices; i++ )
  837.          printf( "\t%3d: %20.20s in %-30.30s\n", i, func_choices[i-1],
  838.                                                          file_choices[i-1] );
  839.       printf( "\nEnter number:" );
  840.       fgets( line, LINE_LEN, stdin );
  841.  
  842.       if( line[0] == '\n' )
  843.          break;
  844.       if( (i = atoi(line)) < 1 || i > num_choices )
  845.          printf( "\nInvalid choice!\007\n" );
  846.       else
  847.          edit( func_choices[i-1], file_choices[i-1] );
  848.    }
  849. }
  850.  
  851. void
  852. edit(func, file)
  853. char *func, *file;
  854. {
  855.             /* execlp will overlay this program with the editor */
  856.    if( num_ctl_patns == 1 )
  857.       sprintf( arg1, arg1_ctl, file );
  858.    else
  859.       sprintf( arg1, arg1_ctl, func, file );
  860.    execlp( pgm_name, pgm_name, arg1, NULL);
  861.                      /* if we're still here, print error msg */
  862.    fprintf( stderr, "getf: exec failed" );
  863.    exit(1);
  864. }
  865. /*
  866. LISTING 4
  867.  
  868. NAME:   getf - locate the source file containing a C function
  869.                and present it in a specified editor.
  870.  
  871. USAGE:  getf [list_file_name] function name
  872.  
  873. DESCRIPTION:    getf looks for the file funcs.txt, which is
  874.         presumed to be a listing of C source file names together
  875.         with a list of the C functions defined in these source
  876.         files; the expected format is
  877.  
  878.                 source_file_1.c:
  879.                         function_1
  880.                         function_2
  881.                         ...
  882.                         function_n;
  883.  
  884.                 source_file_2.c:
  885.                         ...
  886.  
  887.         (This list file can be conveniently built using the companion
  888.         program bldfuncs.c.)
  889.  
  890.                 The editor to be used is specified in the DOS environment
  891.         variable GETFEDIT, which is presumed to have the form:
  892.  
  893.                 editor_name  control_string
  894.  
  895.         where control_string is an sprintf control string which may have
  896.         either one or two occurrences of the pattern "%s": if one such
  897.         pattern exist, it is replaced by the appropriate source file
  898.         name in which the requested function resides; if two such
  899.         patterns exist, the first "%s" is replaced by the function name
  900.         and the second by the source file name.  This latter format allows
  901.         the use of an editor-specific search command to position the
  902.         source file to the requested function automatically.  After
  903.         replacing the "%s" patterns as above, the GETFEDIT string is
  904.         executed via a DOS exec call, thus overlaying the current program
  905.         getf.
  906.  
  907.         The wildcards ?, * and % are allowed in the function name
  908.         argument for getf, and are interpreted as: ? matches any single
  909.         character, * matches the remainder of any string, and % matches
  910.         all characters up to the next underscore or until the end of
  911.         string.
  912.  
  913. EXAMPLES:  Assume the editor is BRIEF; possible GETFEDIT strings might be:
  914.  
  915.                 b %s                    this will simply bring up the
  916.                                         desired source file in BRIEF
  917.                                         without any attempt at positioning
  918.                                         the cursor to the requested function.
  919.  
  920.                 b -m"search_fwd %s" %s  this will bring up the desired
  921.                                         source file and position the cursor
  922.                                         to the first occurrence of the
  923.                                         requested function.
  924.  
  925.                 b -m"funcsrch %s" %s    (see funcsrch.doc for an explanation
  926.                                         of this customized BRIEF macro.)
  927.                                         this will bring up the desired
  928.                                         source file, seek to the end of
  929.                                         the file, then seek backwards for
  930.                                         the LAST occurrence of the requested
  931.                                         function.  In practice, this is the
  932.                                         approach most likely to position the
  933.                                         cursor to the actual definition of
  934.                                         the function.
  935.  
  936.         To illustrate wildcards:
  937.  
  938.                 getf func*              matches func, func1, func_2;
  939.  
  940.                 getf func%              mathces func, func1, but not func_2.
  941.  
  942.                 getf func?_%_*          matches func1_new_, funca_old_stuff,
  943.                                         but not func1_stuff.
  944.  
  945. NOTE:   Remember that to set GETFEDIT in your autoexec.bat file (or in
  946.         any other batch file) you must use TWO percent signs instead of
  947.         one:
  948.                 set GETFEDIT=b -m"funcsrch %%s" %%s
  949.  
  950.         This is necessary to avoid interpretation of the percent signs
  951.         by command.com.
  952. */
  953.  
  954. \ [76703,4265]
  955. \ FORTH.LST                 01-Aug-88 1158
  956.  
  957. \    Keywords: FORTH AUG88
  958.  
  959. \    Source from Martin Tracy's forth column
  960.  
  961. \ _THE FORTH COLUMN_
  962. \ by
  963. \ Martin Tracy
  964.  
  965. \ LISTING 1
  966.  
  967.  
  968.  
  969. \ Dr. C.H. Ting's Simplest Line Drawing Algorithm
  970. HEX
  971. CODE VIDEO ( cx dx ax -- )   \ IBM BIOS video service
  972.    AX POP  DX POP  CX POP   10 INT   NEXT END-CODE
  973. : TEXT    0 0 2 VIDEO ;   \ Return to text mode.
  974. : GRAPH   0 0 4 VIDEO ;   \ Set high-resolution graphics mode.
  975. CODE PLOT ( x y color -- )
  976. \ Given a coordinate pair and a color code,
  977. \ paint one dot on the screen.
  978.    AX POP  0200 # AX ADD   DX POP  CX POP   10 INT
  979.    NEXT END-CODE
  980. DECIMAL
  981.  
  982.  
  983. \ Dr. C. H. Ting's Simplest Line Drawing Algorithm
  984. : draw  ( x1 y1 x2 y2 -- )
  985. \ Draw a straight line between (x1, y1) and (x2,y2).
  986. \ Determine the end condition, where (x1,y1) and (x2,y2)
  987. \ are within one pixel distance.
  988. \ Find the mid point between (x1,y1) and (x2,y2).
  989. \ Insert mid point between 1 and 2, then recurse twice
  990. \ to draw the two segments.
  991.    2over 2over   rot - abs >r
  992.    - abs r> max  2 < if 2drop 3 plot exit then
  993.    2over 2over   rot + 1+ 2/ >r ( y3)
  994.    + 1+ 2/ ( x3) r>  2dup 2rot  recurse  recurse ;
  995.  
  996. : test1   640 0 do  0 0 i 400  draw  10 +loop ;
  997. : test2   400 0 do  0 0 640 i  draw  10 +loop ;
  998.  
  999. /*
  1000. [76703,4265]
  1001. NUTTER.LST                01-Aug-88 29168
  1002.  
  1003.     Keywords: NUTTER AUG88 C SOURCE CONTROL
  1004.  
  1005.     Automatic Module Control in C - source listings from Stewart Nutters
  1006.     article in the August 1988 issue of DDJ.
  1007.  
  1008. LISTING 1
  1009. */
  1010.  
  1011. /* print a visual tree representation of a 'C' program */
  1012. /* cp.c */
  1013.  
  1014. /***********************************************************
  1015.  
  1016.   cprinter - print a visual tree representation
  1017.              of a 'C' program
  1018.  
  1019.   copyright 1987, Stewart A. Nutter
  1020.  
  1021.   Please do not distribute this for profit. For
  1022.   individual use only.
  1023.  
  1024.   written by: Stewart A. Nutter
  1025.  
  1026.  **********************************************************/
  1027.  
  1028. #define MAINMODULE 1
  1029. #include "cpheader.h"
  1030.  
  1031. main( argc, argv )
  1032.  
  1033. char **argv;
  1034. int argc;
  1035.  
  1036. {
  1037. char szName[20];             /* input file name */
  1038. int iRet;
  1039. int l, i, j, k;              /* index variables */
  1040. int sflag;
  1041. int pcnt;
  1042. int tmp;
  1043. int pmax;                    /* max number of xref columns */
  1044. int index;
  1045. FILE *stream;
  1046. struct Pages *p;
  1047. long int total;              /* total number of bytes */
  1048. long int ltotal;             /* total number of lines */
  1049.  
  1050. pFlist = Flist;
  1051. pMlist = Mlist;
  1052. pMnames = Mnames;
  1053.  
  1054. for ( i=0; i<50; i++ )     /* clear out the recursion list */
  1055.    rlist[i] = NULL;
  1056.  
  1057. printf( "\ncp - ver. 1.3, (C) 1987, 1988  Stewart A. Nutter" );
  1058. printf( "\n     written by Stewart A. Nutter\n" );
  1059.  
  1060. /* no arguments - print instructions */
  1061.  
  1062. if ( argc < 2 )
  1063.    {
  1064.    printf( "\ncp listfile [ outfile ] [ /l:xx /w:yy /t:main /s:z ]\n" );
  1065.    printf( "     outfile            = \"prn\" \n" );
  1066.    printf( "     l: page length     = 66       [0, 50-255]\n" );
  1067.    printf( "     w: page width      = 80       [80-255]\n" );
  1068.    printf( "     m: left margin     = 8        [0-30]\n" );
  1069.    printf( "     r: right margin    = 8        [0-30]\n" );
  1070.    printf( "     t: target function = \"main\"\n" );
  1071.    printf( "     s: statistics only = 0        [0=all, 1=stats only]\n" );
  1072.    printf( "\n" );
  1073.    printf( "Notes: 1. Maximum recursive function displacement of 50.\n" );
  1074.    printf( "       2. Maximum number of functions calls is %d.\n", MAXFNCTS );
  1075.    printf( "       3. Maximum number of modules is %d.\n", MAXMODULES );
  1076.    exit( 0 );
  1077.    }
  1078.  
  1079.  
  1080. if ( ( stream = fopen( argv[1], "r" ) ) == NULL )
  1081.    {
  1082.    fprintf( stderr, "\n%s", strerror( errno ) );
  1083.    exit( 1 );
  1084.    }
  1085.  
  1086. /* an output file name was given? */
  1087.  
  1088. index = 2;
  1089.  
  1090. if ( argc > 2 && argv[index][0] != '/' )
  1091.    {
  1092.    output = fopen( argv[2], "w+" );
  1093.    index++;
  1094.    }
  1095. else
  1096.    output = fopen( "prn","w+" );  /* prn device by default */
  1097.  
  1098. for ( i=index; i<argc; i++ )
  1099.    {
  1100.    if ( argv[i][0] == '/' && strlen( argv[i] ) > 3 && argv[i][2] == ':' )
  1101.       {
  1102.       switch ( argv[i][1] )
  1103.          {
  1104.          case 'l' :              /* change the page length */
  1105.             tmp = atoi( &argv[i][3] );
  1106.             if ( ( tmp > 50 && tmp < 256 ) || tmp == 0 )
  1107.               pl = tmp;
  1108.             break;
  1109.  
  1110.          case 'm' :              /* change the left margin */
  1111.             tmp = atoi( &argv[i][3] );
  1112.             if ( tmp >= 0 && tmp <= 30 )
  1113.               lm = tmp;
  1114.             break;
  1115.  
  1116.          case 'r' :              /* change the rignt margin */
  1117.             tmp = atoi( &argv[i][3] );
  1118.             if ( tmp >= 0 && tmp <= 30 )
  1119.               rm = tmp;
  1120.             break;
  1121.  
  1122.          case 's' :              /* set the stats only? */
  1123.             stats = atoi( &argv[i][3] );
  1124.             break;
  1125.  
  1126.          case 't' :              /* change the target function */
  1127.             strcpy( target, &argv[i][3] );
  1128.             break;
  1129.  
  1130.          case 'w' :              /* change the width */
  1131.             tmp = atoi( &argv[i][3] );
  1132.             if ( tmp > 79 && tmp < 256 )
  1133.               pw = tmp;
  1134.             break;
  1135.  
  1136.          }
  1137.       }
  1138.    else
  1139.       {
  1140.       printf( "\nUnknown argument: %s", argv[i] );
  1141.       exit( 1 );
  1142.       }
  1143.    }
  1144.  
  1145. if ( output == NULL )
  1146.    {
  1147.    fprintf( stderr, "\n%s", strerror( errno ) );
  1148.    exit( 1 );
  1149.    }
  1150.  
  1151. width = pw - lm - rm;
  1152. if ( width < 40 )
  1153.    {
  1154.    fprintf( stderr, "\nThe page width is too narrow." );
  1155.    exit( 1 );
  1156.    }
  1157.  
  1158. printf( "\n" );
  1159.  
  1160.  
  1161. /* read the input file for file names */
  1162.  
  1163. while ( !feof( stream ) )
  1164.    {
  1165.    szName[0] = '\0';
  1166.    fgets( szName, 19, stream );
  1167.    if ( ( l = strlen( szName ) ) > 1 )
  1168.       {
  1169.       if ( szName[l - 1] == '\n' )
  1170.          szName[l - 1] = '\0';    /* remove newline char */
  1171.       xref( szName );
  1172.       }
  1173.    }
  1174.  
  1175. /* pointer list for sort */
  1176.  
  1177. for ( i=0, pMlist=Mlist; i<Mqty; i++ )
  1178.    {
  1179.    pm[i] = pMlist++;
  1180.    }
  1181.  
  1182. printf( "\n\nSorting the function list...\n" );
  1183.  
  1184. sflag = 1;
  1185. while ( sflag )                 /* sort the function names */
  1186.    {
  1187.    sflag = 0;
  1188.    for ( i=0; i<Mqty-1; i++ )
  1189.       {
  1190.       if ( strcmp( pm[i]->function, pm[i+1]->function )>0 )
  1191.          {
  1192.          sflag = 1;
  1193.          pMlist = pm[i];
  1194.          pm[i] = pm[i+1];
  1195.          pm[i+1] = pMlist;
  1196.          }
  1197.       }
  1198.    }
  1199. i = find_mod( target );  /* must start with the target function */
  1200.  
  1201. if ( i >= 0 )                   /* 'main' must exist */
  1202.    {
  1203.    depth = 0;
  1204.  
  1205.    printf( "Checking for usage...\n" );
  1206.  
  1207. /* check how many times each function is used */
  1208.  
  1209.    getstats( );
  1210.    depth = 0;
  1211.    bfr[0] = 0;
  1212.  
  1213.    printf( "Starting the printout...\n" );
  1214.  
  1215.    line = 0;
  1216.    if ( stats == 0 )
  1217.       {
  1218.       pm[i]->used = 1;   /* set so main shows up in the list */
  1219.       doprint( i );  /* print the non-library functions */
  1220.  
  1221.       for ( i=0; i<Mqty; i++ )  /* print defined functions now */
  1222.          {
  1223.          fprintf( output, "\n" );
  1224.          line++;
  1225.          if ( pm[i]->used > 1 ) /* must be used more than once */
  1226.             {
  1227.             doprint( i );          /* print the tree structure */
  1228.             }
  1229.          }
  1230.       }
  1231.  
  1232. /* print statistics on the modules */
  1233.  
  1234.    line = 9999;                 /* force a new page */
  1235.    pMnames = Mnames;
  1236.    pagebreak( );
  1237.    leftmargin( output );
  1238.    fprintf( output, "Module statistics :\n" );
  1239.    line++;
  1240.    total = 0L;
  1241.    ltotal = 0L;
  1242.    for ( i=0; i<Mcnt; i++ )  /* print module names & sizes */
  1243.       {
  1244.       pagebreak( );
  1245.       leftmargin( output );
  1246.       fprintf( output,
  1247.               "%-12s - %5u lines, %6ld bytes\n",
  1248.               pMnames->name, pMnames->length,
  1249.               pMnames->size );
  1250.       total += pMnames->size;
  1251.       ltotal += pMnames->length;
  1252.       line++;
  1253.       pMnames++;
  1254.       }
  1255.    fputc( '\n', output );
  1256.    leftmargin( output );
  1257.    fprintf( output,
  1258.            "Total source size = %ld bytes in %ld lines for %d modules\n",
  1259.            total, ltotal, Mcnt );
  1260.  
  1261. /* print the used function page index */
  1262.  
  1263.    line = 9999;                 /* force a new page */
  1264.    pagebreak( );
  1265.    leftmargin( output );
  1266.    fprintf( output, "Function index :\n" );
  1267.    line++;
  1268.    for ( i=0; i<Mqty; i++ )    /* print used function names */
  1269.       {
  1270.       pMlist = pm[i];
  1271.       if ( pMlist->used > 0 )
  1272.          {
  1273.          pagebreak( );
  1274.          leftmargin( output );
  1275.          fprintf( output,
  1276.                  "%-25s - %-12s - used =%d \n",
  1277.                  pMlist->function, ( pMlist->name )->name,
  1278.                  pMlist->used );
  1279.          line++;
  1280.          }
  1281.       }
  1282.  
  1283. /* print the function page cross reference */
  1284.  
  1285.    if ( stats == 0 && pl > 0 )     /* print everything */
  1286.       {
  1287.       pmax = ( int )( width - 27 )/5;
  1288.       line = 9999;                 /* force a new page */
  1289.       pagebreak( );
  1290.       leftmargin( output );
  1291.       fprintf( output, "Function cross reference :\n" );
  1292.       line++;
  1293.       for ( i=0; i<Mqty; i++ )  /* print used function names */
  1294.          {
  1295.          pMlist = pm[i];
  1296.          if ( pMlist->used > 0 )
  1297.             {
  1298.             pagebreak( );
  1299.             leftmargin( output );
  1300.             fprintf( output, "%-25s- ", pMlist->function );
  1301.             p = pMlist->pg;
  1302.             if ( p != NULL )
  1303.                {
  1304.                pcnt = 0;
  1305.                while ( p->next != NULL )
  1306.                   {
  1307.                   fprintf( output, "%4d,", p->pg );
  1308.                   p = p->next;
  1309.                   pcnt++;
  1310.                   if ( pcnt >= pmax )
  1311.                      {
  1312.                      fputc( '\n', output );
  1313.                      leftmargin( output );
  1314.                      fprintf( output, "%27s", " " );
  1315.                      line++;
  1316.                      pcnt = 0;
  1317.                      }
  1318.                   }
  1319.                fprintf( output, "%4d\n", p->pg );
  1320.                line++;
  1321.                }
  1322.             else
  1323.                fprintf( output, "\n" );
  1324.             }
  1325.          }
  1326.       }
  1327.  
  1328. /* print statistics on all unused modules */
  1329.  
  1330.    line = 9999;                 /* force a new page */
  1331.    pagebreak( );
  1332.    leftmargin( output );
  1333.    fprintf( output, "Un-used function list :\n" );
  1334.    line++;
  1335.    pcnt = 0;
  1336.    for ( i=0; i<Mqty; i++ )  /* print unused function names */
  1337.       {
  1338.       pMlist = pm[i];
  1339.       if ( pMlist->used == 0 )
  1340.          {
  1341.          pagebreak( );
  1342.          pcnt++;
  1343.          leftmargin( output );
  1344.          fprintf( output,
  1345.                  "%-25s - %-12s \n",
  1346.                  pMlist->function, ( pMlist->name )->name );
  1347.          line++;
  1348.          }
  1349.       }
  1350.    if ( pcnt == 0 )
  1351.       {
  1352.       leftmargin( output );
  1353.       fprintf( output,
  1354.               "No un-used functions in the list.\n" );
  1355.       }
  1356.  
  1357. /* print module comments */
  1358.  
  1359.    line = 9999;                 /* force a new page */
  1360.    pMnames = Mnames;
  1361.    pagebreak( );
  1362.    leftmargin( output );
  1363.    fprintf( output, "Module comments :\n" );
  1364.    line++;
  1365.    for ( i=0; i<Mcnt; i++ )  /* print module names & comments */
  1366.       {
  1367.       pagebreak( );
  1368.       leftmargin( output );
  1369.       fprintf( output,
  1370.               "%12s -%s\n",
  1371.               pMnames->name, pMnames->cmt );
  1372.       line++;
  1373.       pMnames++;
  1374.       }
  1375.    fprintf( output, "%c", 0x0c );         /* ending formfeed */
  1376.    }
  1377. }
  1378.  
  1379.  
  1380.  
  1381. /* process the file for function names */
  1382.  
  1383. xref( fname )
  1384.  
  1385. char *fname;
  1386.  
  1387. {
  1388. int done;               /* loop termination flag */
  1389. int brace_cnt;          /* count of the open braces */
  1390. int open_paren;         /* open paranthisis count */
  1391. int ret;                /* return value */
  1392. int indx;               /* for/next index */
  1393. int dflg;               /* function definition flag */
  1394. static int wflg = 0;
  1395. char c;                 /* character read from disk file */
  1396. char buffer[50];        /* temporary buffer */
  1397. char bufr[256];         /* temporary buffer */
  1398. register char *p;       /* fast character pointer */
  1399. FILE *stream;           /* module file pointer */
  1400. struct Mod_list *cptr;  /* pointer to the module list structure */
  1401. static char back[] =
  1402.    {8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  1403.     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8};
  1404.  
  1405. printf( "%cProcessing file: %-12s   ", 0x0d, fname );
  1406.  
  1407. if ( ( stream = fopen( fname, "r" ) ) == NULL )
  1408.    return( -1 );
  1409.  
  1410. pp = pc;
  1411. if ( ( pMnames->name = strdup( fname ) ) == NULL )
  1412.    {
  1413.    fprintf( stderr, "Ran out of memory.\n" );
  1414.    exit( 1 );
  1415.    }
  1416. pMnames->length = 0;
  1417. pMnames->size = 0L;
  1418.  
  1419. buffer[0] = 0;
  1420. p = buffer;
  1421.  
  1422. open_paren = 0;
  1423. brace_cnt = 0;
  1424. firstcmt = 0;
  1425. filecmt[0] = 0;
  1426. done = 0;
  1427. ret = 0;
  1428. while ( !ret )
  1429.    {
  1430.    c = getnext( stream );
  1431.    switch ( c )
  1432.       {
  1433.       case '{'  :
  1434.          brace_cnt++;   /* increment the open brace count */
  1435.          break;
  1436.       case '}'  :
  1437.          brace_cnt--;   /* decrement the open brace count */
  1438.          break;
  1439.       case '('  :
  1440.          if ( open_paren == 0 ) /* first open paren only */
  1441.             {
  1442.             open_paren = 1;
  1443.             }
  1444.          wflg = 1;
  1445.          break;
  1446.       case ' ' :              /* skip tabs and spaces */
  1447.       case '\t' :
  1448.          do
  1449.             {
  1450.             c = getnext( stream );
  1451.             }
  1452.          while ( c == '\t' || c == ' ' );
  1453.          if ( c != '(' )
  1454.             wflg = 1;
  1455.          pushc( c );
  1456.          break;
  1457.       case 0x1a :            /* end of the file indicator */
  1458.          ret = 1;
  1459.          wflg = 1;
  1460.       default :
  1461.  
  1462. /* the character must be a variable character */
  1463.  
  1464.          if ( strcheck( c ) )
  1465.             {
  1466.             *p++ = c;
  1467.             *p = 0;
  1468.             }
  1469.          else
  1470.             wflg = 1;
  1471.          break;
  1472.       }
  1473.    if ( wflg )
  1474.       {
  1475.       if ( buffer[0] && ( buffer[0] < '0' || buffer[0] > '9' ) )
  1476.          {
  1477.          done = 1;
  1478.          }
  1479.       else
  1480.          {
  1481.          p = buffer;
  1482.          buffer[0] = 0;
  1483.          open_paren = 0;
  1484.          }
  1485.       wflg = 0;
  1486.       }
  1487.  
  1488. /* if done != 0 there is a token */
  1489.  
  1490.    if ( done )
  1491.       {
  1492.       done = 0;
  1493.       *p = 0;
  1494.  
  1495.       if ( open_paren )               /* functions start with an open paren */
  1496.          {
  1497.          open_paren = 0;
  1498.          if ( brace_cnt == 0 )        /* and no braces */
  1499.             {
  1500.             dflg = 0;
  1501.             for ( indx=0; indx<256 && dflg==0; indx++ )
  1502.                {
  1503.                c = getnext( stream );
  1504.                if ( c == ';' )
  1505.                   dflg = 1;
  1506.                else if ( c == '\n' )
  1507.                   dflg = 2;
  1508.                bufr[indx] = c;
  1509.                }
  1510.             if ( dflg == 0 )
  1511.                {
  1512.                fprintf( stderr, "\nSyntax error: " );
  1513.                fprintf( stderr, "Module description.\n" );
  1514.                bufr[indx] = 0;
  1515.                fprintf( stderr, "\n%s\n", bufr );
  1516.                exit( 1 );
  1517.                }
  1518.  
  1519. /* put the characters back to be read */
  1520.  
  1521.             while ( indx )
  1522.                {
  1523.                pushc( bufr[indx-1] );
  1524.                indx--;
  1525.                }
  1526.  
  1527. /* this is a function definition */
  1528.  
  1529.             if ( dflg == 2 )
  1530.                {
  1531.                printf( "%-40s%s", buffer, back );
  1532.                pMlist->name = pMnames;
  1533.                pMlist->qty = 0;
  1534.                pMlist->ptr = pFlist;
  1535.  
  1536.                /* allocate memory for name */
  1537.  
  1538.                if ( ( pMlist->function = strdup( buffer ) )
  1539.                     == NULL )
  1540.                   {
  1541.                   fprintf( stderr, "\nRan out of memory." );
  1542.                   exit( 1 );
  1543.                   }
  1544.                pMlist->used = 0;
  1545.                pMlist->pg = NULL;
  1546.                cptr = pMlist;
  1547.                pMlist++;
  1548.                Mqty++;
  1549.                if ( Mqty > MAXMODULES )
  1550.                   {
  1551.                   fprintf( stderr,
  1552.                           "Too many new functions\n" );
  1553.                   exit( 1 );
  1554.                   }
  1555.                }
  1556.             }
  1557.          else
  1558.             {
  1559.             cptr->qty += addlist( cptr->ptr,
  1560.                                  buffer, cptr->qty );
  1561.  
  1562.             }
  1563.          }
  1564.       p = buffer;
  1565.       *p = 0;
  1566.       }
  1567.    }
  1568. fclose( stream );
  1569. pMnames->cmt = strdup( filecmt );
  1570. pMnames++;   /* point to the next function data structure */
  1571. Mcnt++;               /* count of the different functions */
  1572. return( ret );
  1573. }
  1574.  
  1575.  
  1576. LISTING 2
  1577.  
  1578. cp.obj : cp.c cpheader.h
  1579.    cl -Ox -AL cp.c -c
  1580.  
  1581. cpfuncts.obj : cpfuncts.c cpheader.h
  1582.    cl -Ox -AL cpfuncts.c -c
  1583.  
  1584. cp.exe : cpfuncts.obj cp.obj
  1585.    link cp+cpfuncts/st:4096;
  1586.  
  1587. /*
  1588. LISTING 3
  1589. */
  1590.  
  1591. /* function module for the program 'cp'
  1592.    the cp program must be compiled with the large model */
  1593.  
  1594. /***********************************************************
  1595.  
  1596.  cpfuncts.c - function module for the program 'cp'
  1597.  
  1598.  copyright 1987, Stewart A. Nutter
  1599.  
  1600.  written by: Stewart A. Nutter
  1601.  
  1602.  ***********************************************************/
  1603.  
  1604.  
  1605. #define MAINMODULE 0
  1606. #include "cpheader.h"
  1607.  
  1608. /* getnext - get the next character from the stream */
  1609.  
  1610. getnext( stream )
  1611.  
  1612. FILE *stream;
  1613.  
  1614. {
  1615. register char c;
  1616. static int qflag=0, cflag=0, eflag=0;
  1617. static int dflag=0, aflag=0, ncnt=0;
  1618. static int fp;
  1619. int b, done;
  1620.  
  1621. done = 1;
  1622. do
  1623.    {
  1624.    if ( ( qflag | cflag | eflag | dflag | aflag ) == 0 )
  1625.       done = 1;
  1626.    c = getchars( stream );
  1627.  
  1628. /* process escape sequence characters */
  1629.  
  1630.    if ( eflag && c != 0x1a )
  1631.       {
  1632.       if ( c >= '0' && c <= '7' && ncnt < 3 )
  1633.          ncnt++;
  1634.       else
  1635.          {
  1636.  
  1637. /* had less than the 3 octal digits */
  1638.  
  1639.          if ( ncnt < 3 && ncnt > 0 )
  1640.             pushc( c );
  1641.          ncnt = 0;
  1642.          eflag = 0;
  1643.          }
  1644.       }
  1645.    else if ( cflag && c != 0x1a )  /* skipping a comment */
  1646.       {
  1647.       if ( firstcmt == 1 )
  1648.          {
  1649.          if ( c != '\n' && strlen( filecmt ) < ( width - 14 ) )
  1650.             {
  1651.             filecmt[fp] = c;
  1652.             fp++;
  1653.             filecmt[fp] = 0;
  1654.             }
  1655.          else
  1656.             {
  1657.             do       /* remove extraneous spaces and tabs */
  1658.                {
  1659.                b = getchars( stream );
  1660.                }
  1661.             while ( b == ' ' || b == '\t' );
  1662.             pushc( b );
  1663.             filecmt[ fp++ ] = ' ';
  1664.             filecmt[ fp ] = '\0';
  1665.             }
  1666.          }
  1667.       if ( c == '*' )
  1668.          {
  1669.          b = getchars( stream );
  1670.          if ( b == '/' )
  1671.             {
  1672.             firstcmt = 2;     /* done with the comment */
  1673.             if ( fp > 0 )
  1674.                filecmt[fp - 1] = 0; /* terminate the line */
  1675.             cflag = 0;
  1676.             }
  1677.          else
  1678.             pushc( b );
  1679.          }
  1680.       }
  1681.    else if ( qflag && c != 0x1a )  /* skipping a string */
  1682.       {
  1683.       if ( c == 0x27 )
  1684.          eflag = 1;
  1685.       else if ( c == '\"' )
  1686.          {
  1687.          pushc( 0x1b );
  1688.          qflag = 0;
  1689.          }
  1690.       }
  1691.    else if ( dflag && c != 0x1a )  /* defines/includes etc. */
  1692.       {
  1693.       if ( c == '\n' )
  1694.          dflag = 0;
  1695.       }
  1696.    else if ( aflag && c != 0x1a )  /* skip a character */
  1697.       {
  1698.       if ( c == 0x27 )
  1699.          {
  1700.          aflag = 0;
  1701.          pushc( 0x1b );
  1702.          }
  1703.       else if ( c == '\\' )
  1704.          eflag = 1;
  1705.       }
  1706.    else
  1707.       {
  1708.       switch ( c )
  1709.          {
  1710.          case '\"' :
  1711.             qflag = 1;
  1712.             break;
  1713.          case 0x27 :
  1714.             aflag = 1;
  1715.             break;
  1716.          case '#' :
  1717.             dflag = 1;
  1718.             break;
  1719.          case '/' :
  1720.             b = getchars( stream );
  1721.             if ( b == '*' )
  1722.                {
  1723.  
  1724.                /* this is the first comment of the file */
  1725.  
  1726.                if ( firstcmt == 0 )
  1727.                   {
  1728.                   firstcmt = 1;
  1729.                   filecmt[0] = 0;
  1730.                   fp = 0;
  1731.                   }
  1732.                cflag = 1;
  1733.                }
  1734.             else
  1735.                {
  1736.                pushc( b );
  1737.                }
  1738.             break;
  1739.          }
  1740.       }
  1741.    if ( aflag || dflag || qflag || eflag || cflag )
  1742.       done=0;
  1743.    }
  1744. while ( !done && c != 0x1a );
  1745. if ( c == 0x1a )
  1746.    {
  1747.    ncnt = 0;
  1748.    aflag = 0;
  1749.    dflag = 0;
  1750.    qflag = 0;
  1751.    eflag = 0;
  1752.    cflag = 0;
  1753.    }
  1754. return( c );
  1755. }
  1756.  
  1757.  
  1758. /* getchars - read inputs from the file */
  1759.  
  1760. getchars( stream )
  1761.  
  1762. FILE *stream;
  1763.  
  1764. {
  1765. register char c;
  1766.  
  1767. if ( pp != pc )
  1768.    c = *--pp;
  1769. else
  1770.    {
  1771.    c = fgetc( stream );
  1772.    if ( c == EOF )
  1773.       c = 0x1a;
  1774.    if ( c == 0x0a )
  1775.       {
  1776.       pMnames->length++;
  1777.       pMnames->size++;     /* count the unseen <cr> */
  1778.       }
  1779.    pMnames->size++;
  1780.    }
  1781. return( c );
  1782. }
  1783.  
  1784. /* pushc - save the char. in a last in first out stack */
  1785.  
  1786. pushc( c )
  1787.  
  1788. char c;
  1789.  
  1790. {
  1791. if ( ( pp - pc ) < 1000 )
  1792.    *pp++ = c;
  1793. else
  1794.    {
  1795.    fprintf( stderr, "\nProgram syntax error:" );
  1796.    fprintf( stderr, " Too many pushed characters.\n" );
  1797.    exit( 1 );
  1798.    }
  1799. }
  1800.  
  1801.  
  1802. /* addlist - add the name to the list if different */
  1803. /*           and if not one of the 'c' key words */
  1804.  
  1805. #define KEYS 5
  1806.  
  1807. addlist( p, buf, cnt )
  1808.  
  1809. struct Func_list *p;
  1810. char *buf;
  1811. int cnt;
  1812.  
  1813. {
  1814. int i, ret;
  1815. static char *keywords[KEYS] =
  1816.    {
  1817.    "while",
  1818.    "if",
  1819.    "for",
  1820.    "switch",
  1821.    "return",
  1822.    };
  1823.  
  1824. for ( i=0; i<KEYS && strcmp( buf, keywords[i] )!=0; i++ )
  1825.    ;
  1826.  
  1827. if ( i < KEYS )
  1828.    return( 0 );
  1829.  
  1830. for ( i=0; i<cnt && strcmp( buf, p->name ); i++ )
  1831.    p++;
  1832.  
  1833. if ( i == cnt )
  1834.    {
  1835.    ret = 1;
  1836.    if ( ( pFlist->name = strdup( buf ) ) == NULL )
  1837.       {
  1838.       fprintf( stderr, "Ran out of memory.\n" );
  1839.       exit( 1 );
  1840.       }
  1841.    pFlist->used = 1;
  1842.    pFlist++;            /* point to the next empty cell */
  1843.    Fqty++;
  1844.    if ( Fqty > MAXFNCTS )
  1845.       {
  1846.       fprintf( stderr, "Too many functions.\n" );
  1847.       exit( 1 );
  1848.       }
  1849.    }
  1850. else
  1851.    {
  1852.    ret = 0;
  1853.    p->used++;
  1854.    }
  1855. return( ret );
  1856. }
  1857.  
  1858.  
  1859. /* find_mod - return the index of the linked list for
  1860.               the indicated function. A -1 means that
  1861.               the function name was not found in the list */
  1862.  
  1863. find_mod( buf )
  1864.  
  1865. char *buf;
  1866.  
  1867. {
  1868. int lo, hi, mid;
  1869. int d;
  1870.  
  1871. lo = 0;
  1872. hi = Mqty - 1;
  1873. mid = ( hi + lo )/2;
  1874.  
  1875. while ( 1 )
  1876.    {
  1877.    d = strcmp( buf, pm[mid]->function );
  1878.    if ( d == 0 )
  1879.       break;
  1880.  
  1881.    if ( lo >= hi )
  1882.       {
  1883.       mid = -1;
  1884.       break;
  1885.       }
  1886.  
  1887.    if ( d < 0 )
  1888.       {
  1889.       hi = mid - 1;
  1890.       }
  1891.    else
  1892.       {
  1893.       lo = mid + 1;
  1894.       }
  1895.    mid = ( hi + lo )/2;
  1896.    }
  1897.  
  1898. return( mid );
  1899. }
  1900.  
  1901.  
  1902. /* doprint - print the function name and sub - functions */
  1903.  
  1904. static char lib[] = {"(library)"};
  1905. static char use[] = {"Used="};
  1906. static char fct[] = {"Functs="};
  1907.  
  1908. doprint( n )
  1909.  
  1910. int n;
  1911. {
  1912. int i, j, k, l, ret;
  1913. struct Mod_list *p;
  1914. struct Func_list *q;
  1915.  
  1916. l = n;
  1917. p = pm[l];
  1918.  
  1919. /* add function to list for recursion check */
  1920.  
  1921. rlist[depth] = p->function;
  1922.  
  1923. pagebreak( );
  1924.  
  1925. setpage( pm[l] );
  1926. ret = page - 1;
  1927. pblock( bfr, p->function, ( p->name )->name, fct, p->qty );
  1928.  
  1929. depth++;
  1930. strcat( bfr, "   |" );
  1931.  
  1932. k = p->qty;
  1933. for ( j=0, q = p->ptr; j<k; j++, q++ )
  1934.    {
  1935.    pagebreak( );
  1936.    i = find_mod( q->name );
  1937.  
  1938.    if ( recur_chk( q->name ) )
  1939.       {
  1940.       leftmargin( output );
  1941.       fprintf( output, "%s\n", bfr );
  1942.       if ( i >= 0 )
  1943.          setpage( pm[i] );
  1944.       pblock( bfr, q->name, "(recursive)", "", 0 );
  1945.       line++;
  1946.       }
  1947.    else
  1948.       {
  1949.       if ( i >= 0 )
  1950.          {
  1951.          if ( pm[i]->used == 1 )
  1952.             {
  1953.  
  1954. /* got a new function */
  1955.  
  1956.             leftmargin( output );
  1957.             fprintf( output, "%s\n", bfr );
  1958.             line++;
  1959.             doprint( i );          /* used only once */
  1960.             }
  1961.          else
  1962.             {
  1963.  
  1964. /* a previously defined function */
  1965.  
  1966.             leftmargin( output );
  1967.             fprintf( output, "%s\n", bfr );
  1968.             setpage( pm[i] );
  1969.             pblock( bfr, q->name, "(defined)",
  1970.                     use, q->used );
  1971.             line++;
  1972.             }
  1973.          }
  1974.       else
  1975.          {
  1976.  
  1977. /* a library function */
  1978.  
  1979.          leftmargin( output );
  1980.          fprintf( output, "%s\n", bfr );
  1981.          pblock( bfr, q->name, lib, use, q->used );
  1982.          line++;
  1983.          }
  1984.       }
  1985.    }
  1986.  
  1987. /* remove the function from the recursion list */
  1988.  
  1989. rlist[depth] = NULL;
  1990. bfr[strlen( bfr )-4] = 0;
  1991. depth--;
  1992. return( ret );
  1993. }
  1994.  
  1995.  
  1996. /* getstats - get the number of times each
  1997.               function is used */
  1998.  
  1999. getstats( )
  2000.  
  2001. {
  2002. register int i;
  2003. int j;
  2004. register struct Func_list *p;
  2005.  
  2006. p = Flist;
  2007.  
  2008. for ( i=0; i<Fqty; i++ )
  2009.    {
  2010.    j = find_mod( p->name );  /* see if the name exists */
  2011.    if ( j >= 0 )
  2012.       pm[j]->used += p->used;
  2013.    p++;
  2014.    }
  2015. }
  2016.  
  2017.  
  2018. /* pblock - print a function block */
  2019.  
  2020. pblock( pre, fptr, mptr, sptr, cnt )
  2021.  
  2022. char *pre, *fptr, *sptr, *mptr;
  2023. int cnt;
  2024.  
  2025. {
  2026. leftmargin( output );
  2027. fprintf( output, "%s %s\n", pre, tline );
  2028. leftmargin( output );
  2029. fprintf( output, "%s-+%-25s|\n", pre, fptr );
  2030. leftmargin( output );
  2031. fprintf( output, "%s |%-12s %8s%3d |\n",
  2032.         pre, mptr, sptr, cnt );
  2033. leftmargin( output );
  2034. fprintf( output, "%s %s\n", pre, tline );
  2035. line += 4;
  2036.  
  2037. }
  2038.  
  2039.  
  2040. /* pagebreak - check for a page break and if so
  2041.                then print the page header */
  2042.  
  2043. pagebreak( )
  2044.  
  2045. {
  2046.    int i;
  2047.    static char title[] = { "C PRINTER  - (c) 1987, 1988  rev. 1.2" };
  2048.  
  2049. if ( pl == 0 && line == 9999 )
  2050.    {
  2051.    fprintf( output, "\n\n\n\n" );
  2052.    line = 0;
  2053.    }
  2054. else if ( pl != 0 )
  2055.    {
  2056.    if ( line > ( pl - 11 ) )
  2057.       {
  2058.       fprintf( output, "%c", 0x0c );
  2059.       line = 0;
  2060.       }
  2061.    if ( line == 0 )
  2062.       {
  2063.       leftmargin( output );
  2064.  
  2065.       fprintf( output, "%s", title );
  2066.       for ( i=strlen( title ); i<width-10; i++ )
  2067.          fputc( ' ', output );
  2068.       fprintf( output, "Page:%4d\n", page );
  2069.  
  2070.       leftmargin( output );
  2071.       for ( i=0; i<width; i++ )
  2072.          fputc( '-', output );
  2073.       fprintf( output, "\n\n" );
  2074.       line = 3;
  2075.       page++;
  2076.       }
  2077.    }
  2078. }
  2079.  
  2080.  
  2081. /* recur_chk - check if the function just called
  2082.                is one being processed */
  2083.  
  2084. recur_chk( buf )
  2085.  
  2086. char *buf;
  2087.  
  2088. {
  2089. register char **p;
  2090. int ret;
  2091.  
  2092. p = rlist;
  2093.  
  2094. while ( *p != NULL && strcmp( *p, buf ) )
  2095.    {
  2096.    p++;
  2097.    }
  2098.  
  2099. if ( *p == NULL )
  2100.    ret = 0;   /* the function was not in the list */
  2101. else
  2102.    ret = 1;   /* found it */
  2103.  
  2104. return ret;
  2105. }
  2106.  
  2107.  
  2108. /* setpage - put the current page number
  2109.              into the linked page list */
  2110.  
  2111. setpage( ptr )
  2112.  
  2113. struct Mod_list *ptr;
  2114.  
  2115. {
  2116. struct Pages *p;
  2117.  
  2118. p = ptr->pg;
  2119. if ( p == NULL )
  2120.    {
  2121.    p = ( struct Pages * )malloc( sizeof( struct Pages ) );
  2122.    if ( p == NULL )
  2123.       {
  2124.       fprintf( stderr,
  2125.               "Ran out of memory for page # list.\n" );
  2126.       exit( 1 );
  2127.       }
  2128.    ptr->pg = p;
  2129.    p->next = NULL;
  2130.    p->pg = page - 1;
  2131.    }
  2132. else
  2133.    {
  2134.    while ( p->next != NULL )
  2135.       p=p->next;
  2136.    p->next = ( struct Pages * )malloc( sizeof( struct Pages ) );
  2137.    if ( p->next == NULL )
  2138.       {
  2139.       fprintf( stderr,
  2140.               "Ran out of memory for page # list.\n" );
  2141.       exit( 1 );
  2142.       }
  2143.    p = p->next;
  2144.    p->next = NULL;
  2145.    p->pg = page - 1;
  2146.    }
  2147. }
  2148.  
  2149.  
  2150. /* strcheck - check if the character is
  2151.               in the variable name set */
  2152.  
  2153. strcheck( c )
  2154.  
  2155. char c;
  2156.  
  2157. {
  2158. if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ||
  2159.      c == '_' || ( c >= '0' && c <= '9' ) )
  2160.    return( 1 );
  2161. else
  2162.    return( 0 );
  2163. }
  2164.  
  2165.  
  2166. stop( )
  2167. {
  2168. printf( "hello" );
  2169. }
  2170.  
  2171.  
  2172. /* print the left margin for the printout */
  2173.  
  2174. leftmargin( output )
  2175.  
  2176.    FILE *output;                    /* the output device pointer */
  2177.  
  2178. {
  2179.    register int i;
  2180.  
  2181. for ( i=0; i<lm; i++ )
  2182.    fputc( ' ', output );
  2183. }
  2184.  
  2185. /*
  2186. LISTING 4
  2187. */
  2188. #include <malloc.h>
  2189. #include <conio.h>
  2190. #include <stdio.h>
  2191. #include <string.h>
  2192. #include <stdlib.h>
  2193.  
  2194. #define MAXFNCTS   4000    /* maximum number of functions */
  2195. #define MAXMODULES 500     /* number of different files */
  2196.  
  2197. struct Func_list           /* function statistics */
  2198.    {
  2199.    char *name;             /* function name */
  2200.    int used;               /* times used in function */
  2201.    };
  2202.  
  2203. struct Pages               /* linked list of pages */
  2204.    {
  2205.    int pg;                 /* page number */
  2206.    struct Pages *next;     /* pointer to next page */
  2207.    };
  2208.  
  2209. struct Module              /* module statistics */
  2210.    {
  2211.    char *name;             /* pointer to the module name */
  2212.    char *cmt;              /* module comment/description */
  2213.    unsigned int length;    /* lines in the module */
  2214.    long size;              /* bytes in the module */
  2215.    };
  2216.  
  2217. struct Mod_list            /* module control stucture */
  2218.    {
  2219.    struct Module *name;    /* pointer to module file name */
  2220.    char *function;         /* name of function in file */
  2221.    struct Func_list *ptr;  /* pointer to the first function */
  2222.    int qty;                /* different functions called */
  2223.    struct Pages *pg;       /* point to the page list */
  2224.    int used;               /* times the function is used */
  2225.    };
  2226.  
  2227. #if MAINMODULE != 0
  2228.  
  2229. struct Module Mnames[MAXMODULES], *pMnames;
  2230. struct Mod_list Mlist[MAXMODULES], *pMlist, *pm[MAXMODULES];
  2231. struct Func_list Flist[MAXFNCTS], *pFlist;
  2232. char *rlist[50];           /* recursion function list */
  2233. int Mqty = 0, Fqty = 0, Mcnt = 0;
  2234. int page=1, line=0, depth=0;
  2235. int fline;
  2236. int firstcmt;
  2237. char bfr[300];
  2238. char tline[] = {"+-------------------------+"};
  2239. char dbl[] = {"  "};
  2240. char vbar[] = {"| "};
  2241. char hbar[] = {"+-"};
  2242. FILE *output;
  2243. char pc[1000] = {0,0,0,0,0,0,0,0,0,0};
  2244. char *pp;
  2245. char filecmt[300];
  2246. int pw = 80;               /* page width */
  2247. int pl = 66;               /* page length */
  2248. int lm = 8;                /* left margin */
  2249. int rm = 8;                /* right margin */
  2250. int width;                 /* the printable page width */
  2251. char target[40] = "main";  /* target function */
  2252. int stats = 0;
  2253.  
  2254. #else
  2255.  
  2256. extern struct Module Mnames[MAXMODULES], *pMnames;
  2257. extern struct Mod_list Mlist[MAXMODULES], *pMlist;
  2258. extern struct Mod_list *pm[MAXMODULES];
  2259. extern struct Func_list Flist[MAXFNCTS], *pFlist;
  2260. extern char *rlist[];       /* recursion function list */
  2261. extern int Mqty, Fqty, Mcnt;
  2262. extern int page, line, depth;
  2263. extern int fline;
  2264. extern int firstcmt;
  2265. extern char bfr[];
  2266. extern char tline[];
  2267. extern char dbl[];
  2268. extern char vbar[];
  2269. extern char hbar[];
  2270. extern FILE *output;
  2271. extern char pc[];
  2272. extern char *pp;
  2273. extern char filecmt[];
  2274. extern int pw;                    /* page width */
  2275. extern int pl;                    /* page length */
  2276. extern int lm;                    /* left margin */
  2277. extern int rm;                    /* right margin */
  2278. extern int width;                 /* the printable page width */
  2279. extern char target[];             /* target function */
  2280. extern int stats;
  2281.  
  2282.  
  2283. [76703,4265]
  2284. PARADI.LST                01-Aug-88 1358
  2285.  
  2286.     Keywords: AUG88 PARADIGM SWAINE
  2287.  
  2288.     Source from Michael Swaines Programming Paradigms column.
  2289.  
  2290. _PROGRAMMING PARADIGMS_
  2291. by
  2292. Michael Swaine
  2293.  
  2294. EXAMPLE 1
  2295.  
  2296. function parallel-sort L
  2297.         if length(L)>1
  2298.         then
  2299.                 split L into L1 and L2
  2300.                 par
  2301.                         parallel-sort L1
  2302.                         parallel-sort L2
  2303.                 merge L1 and L2 into L
  2304.         end if
  2305.         return L
  2306. end function
  2307.  
  2308.  
  2309. EXAMPLE 2
  2310.  
  2311.  
  2312. for pass=1 to ceiling(lgN) do
  2313.         k:=2pass-1
  2314.         par
  2315.                 merge length-k sublists Li and Li+1
  2316.                 merge length-k sublists Li+2 and Li+3
  2317.                 {etc., merging adjacent sublists pairwise}
  2318. end for
  2319.  
  2320. EXAMPLE 3
  2321.  
  2322. repeat forever
  2323.         carry out private activities until hungry
  2324.         repeat until sated
  2325.                 toss coin
  2326.                 if heads
  2327.                 then
  2328.                         firstSide:=left
  2329.                         secondSide:=right
  2330.                 else
  2331.                         firstSide:=right
  2332.                         secondSide:=left
  2333.                 wait until chopstick on firstSide is available
  2334.                 lift chopstick on firstSide
  2335.                 if chopstick on secondSide is not available
  2336.                 then
  2337.                         put down chopstick on firstSide
  2338.                 else
  2339.                         lift chopstick on firstSide
  2340.                         eat until sated
  2341.                         put down chopstick on firstSide
  2342.                         put down chopstick on secondSide
  2343.                 end if
  2344.         end repeat
  2345. end repeat
  2346.  
  2347.  
  2348. EXAMPLE 4
  2349.  
  2350. push input formula F
  2351. repeat until stack is empty or satisfiability is reported
  2352.         pop formula F
  2353.         if F=0
  2354.         then
  2355.                 report "satisfiable"
  2356.         else
  2357.                 choose "appropriate" variable X
  2358.                 split F into FX and FX'
  2359.                 for e in {X,X'} do
  2360.                         if the empty clause is not in Fe
  2361.                         then
  2362.                                 push Fe
  2363.                         end if
  2364.                 end do
  2365.         end if
  2366. end repeat
  2367.  
  2368.  
  2369. [76703,4265]
  2370. PARADI.LST                01-Aug-88 1358               Accesses: 7
  2371.  
  2372. Disposition !
  2373.  
  2374. [76703,4265]
  2375. PORTER.LST                01-Aug-88 7781
  2376.  
  2377.     Keywords: AUG88
  2378.  
  2379.     Kent Porters Structered Progamming column for August 1988
  2380.  
  2381.  
  2382.  
  2383. Disposition !d
  2384. Capture Buffer Transfer
  2385. No error detection/correction
  2386.  
  2387. Opening capture buffer...
  2388. _STRUCTURED PROGRAMMING_
  2389. by
  2390. Kent Porter
  2391.  
  2392. LISTING 1
  2393.  
  2394. PROGRAM sub;
  2395.  
  2396. { Enhanced version of DIR command }
  2397. { Turbo Pascal 4.0 }
  2398. { K. Porter, DDJ, August 88 }
  2399.  
  2400. USES dos, crt;
  2401.  
  2402. TYPE  maskType = STRING [12];
  2403.       pathType = STRING [80];
  2404.  
  2405. VAR   oldDir, searchPath : pathType;
  2406.       fileMask           : maskType;
  2407.       BlockSize, Nfiles  : INTEGER;
  2408.       TotalBytes, TotalK : LONGINT;
  2409.       Thru               : BOOLEAN;
  2410.  
  2411. { ------------------------------------------------------------- }
  2412.  
  2413. PROCEDURE WriteFileInfo (VAR files : SearchRec);
  2414.  
  2415.      { List filename, date, time, etc. }
  2416.  
  2417. VAR   KBytes : LONGINT;
  2418.  
  2419.   FUNCTION TimeStamp : STRING;
  2420.  
  2421.      { Return file date/time by unpacking time field }
  2422.  
  2423.   VAR  stamp             : DateTime;
  2424.        StampStr, WorkStr : STRING [20];
  2425.        ap                : CHAR;
  2426.  
  2427.   BEGIN
  2428.     UnpackTime (files.time, stamp);
  2429.  
  2430.     Str (stamp.month, StampStr);        { Format year as string }
  2431.     IF stamp.month < 10 THEN StampStr := '0' + StampStr;
  2432.     Str (stamp.day, WorkStr);
  2433.     IF stamp.day < 10 THEN
  2434.       StampStr := StampStr + '-0' + WorkStr
  2435.     ELSE
  2436.       StampStr := StampStr + '-'  + WorkStr;
  2437.     Str (stamp.year - 1900, WorkStr);
  2438.     StampStr := StampStr + '-' + WorkStr + '    ';
  2439.  
  2440.     IF stamp.hour > 11 THEN
  2441.       ap := 'p'
  2442.     ELSE
  2443.       ap := 'a';
  2444.     IF stamp.hour > 12 THEN
  2445.       stamp.hour := stamp.hour - 12;
  2446.     Str (stamp.hour, WorkStr);             { Format time string }
  2447.     IF stamp.hour < 10 THEN
  2448.       StampStr := StampStr + '0' + WorkStr
  2449.     ELSE
  2450.       StampStr := StampStr + WorkStr;
  2451.     Str (stamp.min, WorkStr);
  2452.     IF stamp.min < 10 THEN
  2453.       StampStr := StampStr + ':0'
  2454.     ELSE
  2455.       StampStr := StampStr + ':';
  2456.     TimeStamp := StampStr + WorkStr + ap;
  2457.   END;
  2458.  
  2459.  
  2460.   FUNCTION Attribs : STRING;
  2461.  
  2462.      { Return file attributes as a string of indicators }
  2463.  
  2464.   VAR   attrib : STRING [6];
  2465.  
  2466.   BEGIN
  2467.     attrib := '......';
  2468.     WITH files DO BEGIN
  2469.       IF attr AND ReadOnly  <> 0 THEN attrib [6] := 'R';
  2470.       IF attr AND Hidden    <> 0 THEN attrib [5] := 'H';
  2471.       IF attr AND Sysfile   <> 0 THEN attrib [4] := 'S';
  2472.       IF attr AND VolumeID  <> 0 THEN attrib [3] := 'V';
  2473.       IF attr AND Directory <> 0 THEN attrib [2] := 'D';
  2474.       IF attr AND Archive   <> 0 THEN attrib [1] := 'A';
  2475.     END;
  2476.     Attribs := attrib;
  2477.   END;
  2478.  
  2479.  
  2480.   FUNCTION SizeInK : INTEGER;
  2481.  
  2482.      { Return allocated size of file in K }
  2483.  
  2484.   VAR  size : LONGINT;
  2485.  
  2486.   BEGIN
  2487.     IF files.size = 0 THEN
  2488.       SizeInK := 0
  2489.     ELSE BEGIN
  2490.       Size := files.size DIV BlockSize;
  2491.       IF size MOD BlockSize <> 0 THEN
  2492.         Inc (size);
  2493.       IF size = 0 THEN size := 1;
  2494.       SizeInK := (size * BlockSize) DIV 1024;
  2495.     END;
  2496.   END;
  2497.  
  2498.  
  2499. BEGIN  { Body of WriteFileInfo }
  2500.   Write   (files.name);     Gotoxy (21, whereY);
  2501.   Write   (TimeStamp);      Gotoxy (42, whereY);
  2502.   Write   (Attribs);        Gotoxy (53, whereY);
  2503.   Write   (files.size : 6); Gotoxy (64, whereY);
  2504.   KBytes := SizeInK;
  2505.   Writeln (KBytes : 3, 'K');
  2506.  
  2507.   TotalK := TotalK + KBytes;                { Accumulate totals }
  2508.   TotalBytes := TotalBytes + files.size;
  2509.   Inc (NFiles);
  2510. END;
  2511. { ------------------------------------------------------------- }
  2512.  
  2513. PROCEDURE ListFiles (path : pathType; mask : maskType);
  2514.  
  2515.      { List files in currently selected directory using mask }
  2516.  
  2517.  
  2518. VAR  files     : SearchRec;
  2519.      heading   : STRING [160];
  2520.      lineCount : INTEGER;
  2521.  
  2522.  
  2523.   PROCEDURE StartPage;                       { Begin a new page }
  2524.  
  2525.   BEGIN
  2526.     ClrScr;
  2527.     Writeln (heading);
  2528.     Write   ('Name                Date        Time     Attrib');
  2529.     Writeln ('      Bytes     Size');
  2530.     LineCount := 3;
  2531.   END;
  2532.  
  2533.  
  2534.   PROCEDURE CountLines;   { Count lines, start new page if full }
  2535.  
  2536.   VAR   ch : CHAR;
  2537.  
  2538.   BEGIN
  2539.     Inc (LineCount);
  2540.     IF LineCount = 24 THEN BEGIN
  2541.       Gotoxy (1, 25);
  2542.       Write ('-- MORE --');
  2543.       ch := ReadKey;
  2544.       StartPage;
  2545.     END
  2546.   END;
  2547.  
  2548.  
  2549.   PROCEDURE ShowTotals;       { Show total bytes, K, files, etc. }
  2550.  
  2551.   VAR   free, size : REAL;
  2552.  
  2553.   BEGIN
  2554.     size := DiskSize(0);         { Size of default disk in bytes }
  2555.     free := DiskFree(0);
  2556.     Write   (NFiles, ' files, ', TotalBytes, ' bytes, ');
  2557.     Writeln (TotalK, 'K space');
  2558.     Write   (free:1:0, ' bytes free out of ', size:1:0, '
  2559.              total (');
  2560.     Write   ((((size-free) / size) * 100.0) : 5 : 2);
  2561.     Writeln ('% utilization)');
  2562.   END;
  2563.  
  2564.  
  2565. BEGIN  { Body of ListFiles }
  2566.   Heading := 'Directory for ' + mask + ' in ' +
  2567.               path + ':';
  2568.   StartPage;
  2569.   FindFirst (mask, AnyFile, files);
  2570.   IF DosError = 0 THEN
  2571.     REPEAT
  2572.       WriteFileInfo (files);
  2573.       CountLines;
  2574.       FindNext (files);
  2575.     UNTIL DosError <> 0;
  2576.   ShowTotals;
  2577. END;
  2578. { --------------------------- }
  2579.  
  2580. PROCEDURE Separate (VAR path : pathType; VAR mask : maskType);
  2581.  
  2582.      { Break out path and mask from command-line argument }
  2583.  
  2584. VAR   p, c : INTEGER;
  2585.  
  2586. BEGIN
  2587.   path := ParamStr(1);
  2588.   mask := '';
  2589.   p    := Length (path);
  2590.   WHILE (path [p] <> '\') AND (p > 0) DO   { Find last \ in arg }
  2591.     Dec (p);
  2592.   IF p > 0 THEN BEGIN
  2593.     FOR c := (p + 1) TO Length (path) DO
  2594.       mask := mask + path [c];                 { copy file mask }
  2595.     IF p = 1 THEN
  2596.       path [0] := chr (1)                      { backslash only }
  2597.     ELSE
  2598.       path [0] := chr (p - 1);         { truncate path before \ }
  2599.   END;
  2600. END;
  2601. { --------------------------- }
  2602.  
  2603. FUNCTION AllocInfo : INTEGER;
  2604.  
  2605.      { Returns the size of a disk allocation unit in bytes }
  2606.  
  2607. VAR   reg : registers;
  2608.  
  2609. BEGIN
  2610.   reg.ah := $1B;
  2611.   Intr ($21, reg);                        { DOS Int 21h, Fcn 1B }
  2612.   AllocInfo := reg.al * reg.cx;        { sec/cluster * sec size }
  2613. END;
  2614. { --------------------------- }
  2615.  
  2616. PROCEDURE Check (VAR mask : maskType);
  2617.  
  2618.      { Check file mask, complete if necessary }
  2619.  
  2620. BEGIN
  2621.   IF mask [1] = '.' THEN                 { if form is '.EXT'... }
  2622.     mask := '*' + mask;
  2623.   IF pos ('.', mask) = 0 THEN        { if mask has no period... }
  2624.     mask := mask + '.*';
  2625. END;
  2626. { --------------------------- }
  2627.  
  2628. BEGIN   { Main program }
  2629.   GetDir (0, oldDir);              { Save the current directory }
  2630.   BlockSize  := AllocInfo;                 { Initialize globals }
  2631.   TotalBytes := 0;
  2632.   TotalK     := 0;
  2633.   NFiles     := 0;
  2634.   Thru       := FALSE;
  2635.   fileMask   := '*.*';               { Initialize mask and path }
  2636.   searchPath := oldDir;
  2637.  
  2638.   IF ParamCount < 1 THEN              { No command-line arg, so }
  2639.     BEGIN                          { show all files in curr dir }
  2640.       ListFiles (searchPath, fileMask);
  2641.       Thru := TRUE;
  2642.     END;
  2643.  
  2644.   {$I-}                           { Disable auto error checking }
  2645.   IF not thru THEN BEGIN  { Is command SUB <dir> or SUB \<dir>? }
  2646.     searchPath := ParamStr(1);
  2647.     ChDir (searchPath);                  { Try to set directory }
  2648.     IF IOResult = 0 THEN BEGIN             { List if successful }
  2649.       {$I+}                          { Re-enable error checking }
  2650.       ListFiles (searchPath, fileMask);
  2651.       Thru := TRUE;
  2652.     END;
  2653.   END;
  2654.  
  2655.   {$I-}
  2656.   IF not thru THEN BEGIN            { Is command SUB <dir\*.*>? }
  2657.     Separate (searchPath, fileMask);
  2658.     ChDir (searchPath);                  { Try to set directory }
  2659.     IF IOResult = 0 THEN
  2660.       IF Length (FileMask) > 0 THEN BEGIN
  2661.         Check (fileMask);
  2662.         ListFiles (searchPath, fileMask);
  2663.         Thru := TRUE;
  2664.       END;
  2665.   END;
  2666.  
  2667.   IF not thru THEN BEGIN                  { Is command SUB *.*? }
  2668.     fileMask   := ParamStr(1);
  2669.     Check (fileMask);
  2670.     ListFiles (oldDir, fileMask);
  2671.     Thru := TRUE;
  2672.   END;
  2673.  
  2674.   IF not thru THEN
  2675.     Writeln ('PATH NOT FOUND');
  2676.  
  2677.   ChDir (oldDir);                    { Restore former directory }
  2678. END.
  2679.